package cn.xzqwjw.taskmanager.service.impl;

import cn.xzqwjw.taskmanager.common.customEnum.ArticleStatusEnum;
import cn.xzqwjw.taskmanager.common.customEnum.ResponseCodeEnum;
import cn.xzqwjw.taskmanager.common.exception.CustomException;
import cn.xzqwjw.taskmanager.domain.vo.ResponseVo;
import cn.xzqwjw.taskmanager.utils.*;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.xzqwjw.taskmanager.domain.pojo.Article;
import cn.xzqwjw.taskmanager.service.ArticleService;
import cn.xzqwjw.taskmanager.repository.ArticleMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author rush
 */
@EnableTransactionManagement
@Service("ArticleService")
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>
    implements ArticleService {

  private final ArticleMapper articleMapper;

  @Autowired
  public ArticleServiceImpl(ArticleMapper articleMapper) {
    this.articleMapper = articleMapper;
  }

  @Override
  public String add(Article article) {
    if (save(article)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_CREATED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_INSERT);
    }
  }

  @Override
  public int add4Task(Article article) {
    if (save(article)) {
      return article.getId();
    } else {
      return 0;
    }
  }

  /**
   * 逻辑删除，需验证管理员id是否是当前登录管理员的id，防止删除其他人文章
   */
  @Override
  public String delById(int idArticle) {
    CommonUtil.checkId(idArticle);
    UpdateWrapper<Article> wrapper = new UpdateWrapper<>();
    wrapper.set("flag_deleted", 1)
        .set("status", ArticleStatusEnum.DELETE.getValue())
        .set("id_signer", 0)
        .eq("id", idArticle);
    if (articleMapper.update(null, wrapper) > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_DELETED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_DELETE);
    }
  }

  /**
   * 真实删除，需验证管理员id是否是当前登录管理员的id，防止删除其他人文章
   */
  @Override
  public String delByIdReal(int idArticle) {
    CommonUtil.checkId(idArticle);
    if (articleMapper.delByIdReal(idArticle) > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_DELETED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_DELETE);
    }
  }

  /**
   * 批量删除（文章移动到回收站）
   */
  @Override
  public String batchDel(String ids) {
    // 普通编辑将文章批量移动到回收站，普通编辑只能删除自己的文章，不能删除其他人的文章
    // status='1' flag_deleted=1
    articleMapper.batchDel(ids);
    if (batchSetIdSigner(0, ids) > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_DELETED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_DELETE);
    }
  }

  /**
   * 批量真实删除（回收站中删除文章）
   */
  @Override
  public String batchDelReal(String ids) {
    if (articleMapper.batchDelReal(ids) > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_DELETED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_DELETE);
    }
  }

  @Override
  public String modifyAll(Article article) {
    if (updateById(article)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_UPDATED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_UPDATE);
    }
  }

  @Override
  public boolean modifyAll4Task(Article article) {
    return updateById(article);
  }

  /**
   * 设置文章状态（流程2：草稿 <-> 签发）
   * action = "draft"，不需 idAdmin
   * 撤销提交审核
   * action = "uncheck"，不需 idAdmin
   * 草稿提交审核 / 已签发文章设为待审
   * action = "signed"，idAdmin 是签发管理员的id
   * 签发编辑将待审文章直接设为签发
   */
  @Override
  public String patchStatus(int idAdmin, int idArticle, String action) {
    CommonUtil.checkId(idAdmin, idArticle);
    if (!StringUtils.hasText(action)) {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    UpdateWrapper<Article> wrapper = new UpdateWrapper<>();
    wrapper.eq("id", idArticle);
    if (ArticleStatusEnum.DRAFT.getCode().equalsIgnoreCase(action)) {
      // 0：草稿 撤销提交审核
      wrapper.set("id_signer", 0).set("flag_deleted", 0)
          .set("status", ArticleStatusEnum.DRAFT.getValue());
    } else if (ArticleStatusEnum.UNCHECK.getCode().equalsIgnoreCase(action)) {
      // 2：待审 草稿提交审核 / 已签发文章设为待审
      wrapper.set("id_signer", 0).set("status", ArticleStatusEnum.UNCHECK.getValue());
    } else if (ArticleStatusEnum.SIGNED.getCode().equalsIgnoreCase(action)) {
      // 4：已签发 签发编辑将待审文章直接设为签发
      wrapper.set("id_signer", idAdmin).set("status", ArticleStatusEnum.SIGNED.getValue());
    } else {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    // 注意 mybatis-plus 的 update 会在自动添加  WHERE flag_deleted=false 的条件
    if (articleMapper.update(null, wrapper) > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_PATCHED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_PATCH);
    }
  }

  /**
   * mybatis-plus 的 update 会自动添加  WHERE flag_deleted=false 的条件
   * 因此在xml里单独写恢复sql语句
   */
  @Override
  public String unDel(int idArticle) {
    CommonUtil.checkId(idArticle);
    if (articleMapper.unDel(idArticle) > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_PATCHED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_PATCH);
    }
  }

  /**
   * 批量设置文章状态（流程2：草稿 <-> 签发）
   * action = "draft"，不需 idAdmin
   * 批量撤销提交审核 / 从回收站恢复文章
   * action = "uncheck"，不需 idAdmin
   * 批量将草稿提交审核 / 批量将已签发文章设为待审
   * action = "signed"，idAdmin 是签发管理员的id
   * 签发编辑批量将待审文章直接设为签发
   */
  @Override
  public String batchPatchStatus(int idAdmin, String ids, String action) {
    CommonUtil.checkId(idAdmin);
    CommonUtil.checkIds(ids);
    if (!StringUtils.hasText(action)) {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    int rows;
    if (ArticleStatusEnum.DRAFT.getCode().equalsIgnoreCase(action)) {
      // 0：草稿 批量撤销提交审核 / 从回收站恢复文章
      // status='0' flag_deleted=0
      batchUnDel(ids);
      rows = batchSetIdSigner(0, ids);
    } else if (ArticleStatusEnum.UNCHECK.getCode().equalsIgnoreCase(action)) {
      // 批量将草稿提交审核 / 批量将已签发文章设为待审
      batchSetStatus(ArticleStatusEnum.UNCHECK.getValue(), ids);
      rows = batchSetIdSigner(0, ids);
    } else if (ArticleStatusEnum.SIGNED.getCode().equalsIgnoreCase(action)) {
      // 签发编辑批量将待审文章直接设为签发
      batchSetStatus(ArticleStatusEnum.SIGNED.getValue(), ids);
      rows = batchSetIdSigner(idAdmin, ids);
    } else {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    if (rows > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_PATCHED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_PATCH);
    }
  }

  /**
   * 批量移动到其他栏目
   */
  @Override
  public String batchMove(int idCategory, String ids) {
    Map<String, Object> paramMap = new HashMap<>(16);
    paramMap.put("idCategory", idCategory);
    paramMap.put("ids", ids);
    if (articleMapper.batchMove(paramMap) > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_PATCHED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_PATCH);
    }
  }

  @Override
  public String queryById(int id) {
    Map<String, Object> articleMap = articleMapper.getDetailById(id);
    if (CollectionUtils.isEmpty(articleMap)) {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    // 更新点击次数
    int rows = articleMapper.updateClick(id);
    if (rows > 0) {
      return JsonUtil.obj2Json(ResponseVo.success(articleMap));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_PATCH);
    }
  }

  // ========== 后端管理员用到的函数和方法 ==========

  /**
   * 文章管理员分页获取所有栏目或指定栏目下所有已审未审文章、回收站文章
   * flagDeleted=0 表示所有未删文章，=1 表示回收站文章
   * editorId=0 表示调用所有编辑的文章，editorId>0 表示调用某编辑的所有文章
   * categoryId=0 表示调用所有文章，categoryId>0 表示调用某栏目下所有文章
   */
  @Override
  public String listPage4Admin(int pageCurrent, int pageSize,
                               int flagDeleted, String status,
                               int idCategory, int idEditor) {
    if (StringUtils.hasText(status)) {
      // 前端传过来的 status 是 draft、delete、uncheck、signed，
      // 要转换成 0、1、2、4，如果没有对应的则报异常
      status = ArticleStatusEnum.getValueByCode(status.toLowerCase()).getValue();
    } else {
      status = "";
    }
    Page<Map<String, Object>> page = CommonUtil.getPage(pageCurrent, pageSize);
    Map<String, Object> paramMap = new HashMap<>(16);
    paramMap.put("flagDeleted", flagDeleted);
    paramMap.put("status", status);
    paramMap.put("editorId", idEditor);
    paramMap.put("categoryId", idCategory);
    List<Map<String, Object>> listData = articleMapper.selectPage4Admin(page, paramMap).getRecords();
    return ResponseUtil.writePageData(page, listData, pageSize);
  }

  /**
   * 文章管理员根据标题关键字词搜索文章，返回分页数据
   */
  @Override
  public String search4Admin(int pageCurrent, int pageSize,
                             String keyword, int idEditor) {
    Page<Map<String, Object>> page = CommonUtil.getPage(pageCurrent, pageSize);
    Map<String, Object> paramMap = new HashMap<>(16);
    paramMap.put("keyword", keyword);
    paramMap.put("editorId", idEditor);
    List<Map<String, Object>> listData = articleMapper.search4Admin(page, paramMap).getRecords();
    return ResponseUtil.writePageData(page, listData, pageSize);
  }

  /**
   * 验证参数管理员id是否是已登录管理员的id，防止操作其他管理员的文章
   */
  @Override
  public void checkAdmin(HttpServletRequest request, int idAdmin) {
    if (idAdmin != ConvertUtil.str2Int(JwtUtil.getIdFromRequestJwt(request))) {
      throw new CustomException(ResponseCodeEnum.FORBIDDEN);
    }
  }

  // ========== 前端用户用到的函数和方法 ==========

  /**
   * 前端分页获取所有栏目或指定栏目下或一组栏目ids下所有已签发文章
   */
  @Override
  public String listPage4Front(int pageCurrent, int pageSize, String categoryIds) {
    CommonUtil.checkIds(categoryIds);
    Page<Map<String, Object>> page = CommonUtil.getPage(pageCurrent, pageSize);
    List<Map<String, Object>> listData = articleMapper.selectPage4Front(page, categoryIds).getRecords();
    return ResponseUtil.writePageData(page, listData, pageSize);
  }

  @Override
  public String search4Front(int pageCurrent, int pageSize, String keyword) {
    Page<Map<String, Object>> page = CommonUtil.getPage(pageCurrent, pageSize);
    List<Map<String, Object>> listData = articleMapper.search4Front(page, keyword).getRecords();
    return ResponseUtil.writePageData(page, listData, pageSize);
  }

  // ========== 用到的私有函数和方法 ==========

  /**
   * 批量设置文章的Status
   */
  private void batchSetStatus(String status, String ids) {
    Map<String, Object> paramMap = new HashMap<>(16);
    paramMap.put("status", status);
    paramMap.put("ids", ids);
    articleMapper.batchSetStatus(paramMap);
  }

  /**
   * 批量设置审核文章管理员id
   */
  private int batchSetIdChecker(int idChecker, String ids) {
    Map<String, Object> paramMap = new HashMap<>(16);
    paramMap.put("idChecker", idChecker);
    paramMap.put("ids", ids);
    return articleMapper.batchSetIdChecker(paramMap);
  }

  /**
   * 批量设置审核文章管理员id
   */
  private int batchSetIdSigner(int idSigner, String ids) {
    Map<String, Object> paramMap = new HashMap<>(16);
    paramMap.put("idSigner", idSigner);
    paramMap.put("ids", ids);
    return articleMapper.batchSetIdSigner(paramMap);
  }

  /**
   * 批量恢复（文章移动到草稿箱）
   */
  private void batchUnDel(String ids) {
    articleMapper.batchUnDel(ids);
  }

}




